package com.example.springbootdemo.service;

import io.minio.*;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.http.Method;
import io.minio.messages.Item;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

@Service
public class MinioService {
    
    @Autowired
    private MinioClient minioClient;
    
    @Value("${oss.token}")
    private String ossToken;
    
    private static final String BUCKET_NAME = "bucket-test1";
    
    /**
     * 上传文件
     */
    public String uploadFile(MultipartFile file) throws Exception {
        // 检查bucket是否存在，不存在则创建
        boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(BUCKET_NAME).build());
        if (!bucketExists) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(BUCKET_NAME).build());
        }
        
        // 生成文件名
        String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();
        
        // 上传文件
        minioClient.putObject(
            PutObjectArgs.builder()
                .bucket(BUCKET_NAME)
                .object(fileName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build()
        );
        
        return fileName;
    }
    
    /**
     * 从OSS下载并上传到MinIO
     */
    public String downloadAndUploadFromOss(String ossUrl) throws Exception {
        // 1. 下载文件
        HttpHeaders headers = new HttpHeaders();
        headers.set("token", ossToken);
        headers.set("deviceType", "3");
        HttpEntity<String> entity = new HttpEntity<>(headers);

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<byte[]> response = restTemplate.exchange(
            ossUrl, HttpMethod.GET, entity, byte[].class);

        if (response.getStatusCode().value() != 200) {
            throw new RuntimeException("下载失败，状态码: " + response.getStatusCode());
        }

        byte[] fileBytes = response.getBody();
        if (fileBytes == null || fileBytes.length == 0) {
            throw new RuntimeException("下载的文件为空");
        }

        // 2. 生成文件名
        String fileName = System.currentTimeMillis() + "_" + extractFileName(ossUrl);
        
        // 3. 检查bucket是否存在，不存在则创建
        boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(BUCKET_NAME).build());
        if (!bucketExists) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(BUCKET_NAME).build());
        }

        // 4. 上传到MinIO
        try (InputStream is = new ByteArrayInputStream(fileBytes)) {
            minioClient.putObject(
                PutObjectArgs.builder()
                    .bucket(BUCKET_NAME)
                    .object(fileName)
                    .stream(is, fileBytes.length, -1)
                    .contentType("application/octet-stream")
                    .build()
            );
        }
        
        return fileName;
    }
    
    /**
     * 从URL中提取文件名
     */
    private String extractFileName(String url) {
        String fileName = url.substring(url.lastIndexOf('/') + 1);
        // 如果文件名包含查询参数，去掉查询参数
        if (fileName.contains("?")) {
            fileName = fileName.substring(0, fileName.indexOf("?"));
        }
        // 如果文件名为空，使用默认名称
        if (fileName.isEmpty()) {
            fileName = "downloaded_file";
        }
        return fileName;
    }
    
    /**
     * 获取文件列表
     */
    public List<FileInfo> listFiles() throws Exception {
        List<FileInfo> fileList = new ArrayList<>();
        
        Iterable<Result<Item>> results = minioClient.listObjects(
            ListObjectsArgs.builder()
                .bucket(BUCKET_NAME)
                .build()
        );
        
        for (Result<Item> result : results) {
            Item item = result.get();
            if (!item.isDir()) {
                FileInfo fileInfo = new FileInfo();
                fileInfo.setName(item.objectName());
                fileInfo.setSize(item.size());
                fileInfo.setLastModified(item.lastModified().toString());
                fileInfo.setUrl(getFileUrl(item.objectName()));
                fileList.add(fileInfo);
            }
        }
        
        return fileList;
    }
    
    /**
     * 删除文件
     */
    public void deleteFile(String fileName) throws Exception {
        minioClient.removeObject(
            RemoveObjectArgs.builder()
                .bucket(BUCKET_NAME)
                .object(fileName)
                .build()
        );
    }
    
    /**
     * 获取文件下载URL
     */
    public String getFileUrl(String fileName) {
        return "http://192.168.1.6:9000/" + BUCKET_NAME + "/" + fileName;
    }
    
    /**
     * 获取预签名下载URL
     */
    public String getPresignedUrl(String fileName) throws Exception {
        return minioClient.getPresignedObjectUrl(
            GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(BUCKET_NAME)
                .object(fileName)
                .expiry(60 * 10) // 10分钟有效
                .build()
        );
    }
    
    /**
     * 文件信息类
     */
    public static class FileInfo {
        private String name;
        private long size;
        private String lastModified;
        private String url;
        
        // Getters and Setters
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        
        public long getSize() { return size; }
        public void setSize(long size) { this.size = size; }
        
        public String getLastModified() { return lastModified; }
        public void setLastModified(String lastModified) { this.lastModified = lastModified; }
        
        public String getUrl() { return url; }
        public void setUrl(String url) { this.url = url; }
    }
} 